# coding: utf-8

import datetime
import re
import json

from flask import request, jsonify, current_app
from sqlalchemy import or_, and_

from common.bid_notify.message import MessageNotify
from .. import db
from ..models import get_timestamp
from common.constant import BidQueueStatus
from . import axb_bp
from .models import (
    VirtualNumber, CallOrderForLT, SmsOrder,
    QueryCallNumberRecord, QuerySmsNumberRecord, NumberPoolForLT
)
from .constant import VirtualNumberValid, filter_key_list
from app.constant import Choice
from app.op.models import User, Demand, UserInfo, Partic, DemandClient, \
    BidUserQueue, RenewableDemand
from app.op.constant import DemandStatus, ParticStatus, UserType, \
    UserCreditRule, FollowType, DemandClientSource, SEMGroup, \
    OperatedStatus, ContactState
from app.ccws.models import create_outbound_mission
from app.ccws.constant import CallReason
from app.enterprise.models import Enterprise


# 联通实时模式，是移客通请求我们的接口，暂时不对签名做校验
# 先把相关信息写在这里备用吧
# appKey=2292848467428753
# appSecret=67w7QqnN7549515X3C96vu2U9B8N221h

@axb_bp.route('/query_call_number', methods=['POST'])
def query_call_number():
    """
    refactoring by zhouhl 2018-04-08
    呼叫号码查询，联通实时模式

    axb 用于项目流程
    axn 用于客服系统外呼(for_sms=False)、短信拉新(for_sms=True)等场景
    number_pool_for_lt.enterprise_id <> 0 为专用于金牌/银牌公司首页推广

    0. 查询改虚拟号是否专用于金牌/银牌公司首页推广
        0.1 直接返回该公司对应账户的手机号码

    1. 发布项目使用的axb
        此时客户的号码为 tel_a，工程商的号码为 tel_b，且 for_sms=False
        1.1 竞价模式下，每个竞价成功的工程商与客户之间有一条axb关系
        1.2 如果超时未联系，则会解绑该虚拟关系，并对新竞价成功者与客户进行绑定
        1.3 如果客户回拨，则返回工程商号码

    2. 客服系统外呼使用的axn
        此时客户的号码为 tel_a，且 for_sms=False
        2.1 主叫号码不是 tel_a 时，判断为客服系统外呼，返回客户号码即 tel_a
        2.2 主叫号码是 tel_a 时，判断为客户回拨，播放IVR 33420180525141430.wav

    3. 短信营销的axn
        此时营销对象的号码为 tel_a，且 for_sms=True
        3.1 主叫号码为 tel_a 时，转接至 075526926431，万屏汇的一个无人接听的固话
    """
    data = request.get_json()
    query_call_number_record = QueryCallNumberRecord.create(**data)
    # 主叫真实号
    caller = data['caller']
    # 被叫虚拟号
    called = data['called']

    code = -1
    message = ''
    # 主叫分配号，用于在被叫端显示。直接在被叫端显示虚拟号
    caller_show = ''
    # 主叫播放IVR
    caller_voice = ''
    # 被叫真实号
    called_show = ''
    # 被叫播放IVR
    called_voice = ''

    # 拨打的虚拟号是否用于金牌/银牌公司首页推广
    # 企业推广首页使用的虚拟号不创建 VirtualNumber 记录
    tmp_number = NumberPoolForLT.get_by_args(tel=called)
    if tmp_number and tmp_number.enterprise_id:
        # 返回企业主账号的mobile
        enterprise = Enterprise.get_by_id(tmp_number.enterprise_id)
        tmp_user = User.get_by_id(enterprise.user_id) if enterprise else None
        if tmp_user:
            code = 0
            caller_show = called
            called_show = tmp_user.mobile
            query_call_number_record.return_code = code
            query_call_number_record.return_tel = called_show
            query_call_number_record.return_message = message
            response = {
                'code': code,
                'message': message,
                'data': {
                    'caller_show': caller_show,
                    'caller_voice': caller_voice,
                    'called_show': called_show,
                    'called_voice': called_voice,
                    'other': {},
                }
            }
            return jsonify(response)

    demand_id = None
    # STEP1. 查询axb关系
    # 先判断是否工程商中标有效期间内拨打tel_x
    # 再判断是否客户拨打tel_x
    # 最后判断是否工程商超时未联系后拨打tel_x
    vir_num_record = VirtualNumber.get_by_args(
        tel_b=caller,
        tel_x=called,
        for_sms=False,
        valid=VirtualNumberValid.VALID.value
    )
    # 工程商中标有效期间内拨打tel_x
    if vir_num_record:
        code = 0
        caller_show = vir_num_record.tel_x
        called_show = vir_num_record.tel_a
        # 工程商拨打axb号码时，修改partics和demand的状态
        if vir_num_record.demand_id:
            demand = Demand.get_by_id(vir_num_record.demand_id)
            demand_id = demand.id
            if demand:
                supplier = User.get_by_args(mobile=caller)
                if supplier:
                    # 取出待联系工程商, 或者是派单抢单成功但未联系的工程商
                    p = Partic.query.filter(
                        Partic.demand_id == demand.id,
                        Partic.supplier_id == supplier.id,
                        or_(
                            Partic.status == ParticStatus.NOT_CONTACT.value,
                            and_(
                                Partic.status == ParticStatus.SUCCEED.value,
                                Partic.demand_status.in_([
                                    DemandStatus.DISPATCHING.value,
                                    DemandStatus.MASTER_DISPATCHING.value
                                ]),
                                Partic.contact_state == ContactState.NO.value
                            )
                        )
                    ).first()

                    if p:
                        p.contact_state = ContactState.YES.value
                        p.follow_type = FollowType.KEEP.value
                        p.status = ParticStatus.SUCCEED.value

                        # 修改中标队列状态
                        queue = BidUserQueue.get_by_args(partic_id=p.id)
                        if queue:
                            queue.status = BidQueueStatus.CALLED
                        # 增加工程商成就值
                        supplier = User.get_by_id(p.supplier_id)
                        supplier.credit += UserCreditRule.WIN_BID.value

                        # 二次发布的项目成功以后需要增加成功数量
                        renewable_demand = RenewableDemand.get_by_args(
                            demand_id=demand_id
                        )
                        # 二次发布的项目
                        if (renewable_demand and
                                renewable_demand.operated_status == OperatedStatus.REPUBLISH.value):
                            renewable_demand.recovery_success_count += 1

                        # 更新用户的成交次数
                        UserInfo.default_user_info(p.supplier_id).bid_count += 1
    else:
        # 客户拨打tel_x
        vir_num_record = VirtualNumber.get_by_args(
            tel_a=caller,
            tel_x=called,
            for_sms=False,
            valid=VirtualNumberValid.VALID.value
        )
        if vir_num_record and vir_num_record.tel_b != '':
            code = 0
            caller_show = vir_num_record.tel_x
            called_show = vir_num_record.tel_b

    # 判断是否工程商超时未联系
    if code == -1 and not vir_num_record and caller not in SEMGroup.values():
        # 防止以前超时未联系的记录冲突，所以根据id取最近的记录
        # 所以 if 里面会有 not vir_num_record 的条件
        vir_num_record = VirtualNumber.query.filter_by(
            tel_b=caller,
            tel_x=called,
            for_sms=False,
            valid=VirtualNumberValid.INVALID.value
        ).order_by(
            VirtualNumber.id.desc()
        ).first()
        if vir_num_record:
            code = 408
            message = '超时未联系'
            caller_voice = '33420171106110523.wav'

    # 无axb关系，查axn关系
    if code == -1:
        # 客服系统外呼使用的axn
        vir_num_record = VirtualNumber.get_by_args(
            tel_x=called,
            tel_b='',
            for_sms=False,
            valid=VirtualNumberValid.VALID.value
        )
        if vir_num_record:
            if caller != vir_num_record.tel_a:
                code = 0
                caller_show = vir_num_record.tel_x
                called_show = vir_num_record.tel_a
            else:
                code = 404
                message = '绑定关系不存在'
                caller_voice = '33420180525141430.wav'

    if code == -1:
        # 短信营销的axn
        vir_num_record = VirtualNumber.get_by_args(
            tel_x=called,
            tel_b='',
            for_sms=True,
        )
        if vir_num_record:
            # 短信营销的虚拟号，直接转到'075526926431'
            code = 0
            caller_show = called
            called_show = '075526926431'
            # 拉新回呼默认标为疑似工程商
            user = User.get_by_args(mobile=caller, sms_marketing_obj=True)
            if user:
                # 置为已回应
                if not user.sms_marketing_respond:
                    user.sms_marketing_respond = True
                    user.sms_marketing_respond_datetime = datetime.datetime.now()

    # axb 与 axn 都查找不到相应的虚拟号关系
    if code == -1:
        code = 404
        message = '绑定关系不存在'
        caller_voice = '33420180525141430.wav'

    query_call_number_record.return_code = code
    query_call_number_record.return_tel = called_show
    query_call_number_record.return_message = message
    response = {
        'code': code,
        'message': message,
        'data': {
            'caller_show': caller_show,
            'caller_voice': caller_voice,
            'called_show': called_show,
            'called_voice': called_voice,
            'other': {},
        }
    }

    if demand_id:
        db.session.commit()
        Partic.clear_demand_partic_cache_data(current_app.redis, demand_id)
    return jsonify(response)


@axb_bp.route('/push_call_order', methods=['POST'])
def push_call_order():
    """
    通话话单推送，联通实时模式
    """
    try:
        data = request.get_json()
        for key in filter_key_list:
            if not data.get(key, None):
                data[key] = None
        record = CallOrderForLT.create(**data)
        # 判断是否客户号码是否外泄，非本平台客户拨打电话
        caller = data.get('caller')     # 主叫
        called = data.get('called')     # 被叫
        called_show = data.get('called_show')     # 虚拟号
        tmp_user = User.get_by_args(mobile=caller)
        tmp_virtual_number = VirtualNumber.get_by_args(
            tel_a=called,
            valid=VirtualNumberValid.VALID.value
        )
        if not tmp_user and tmp_virtual_number:
            if tmp_virtual_number.demand_id:
                record.outer_user = Choice.YES.value

        # add by zhouhl 2017-10-24
        # 短信营销的工程商回拨虚拟号，将其标记为有回应
        markrting_user = User.get_by_args(
            mobile=caller,
            sms_marketing_obj=True,
            sms_marketing_respond=False,
        )
        if markrting_user:
            markrting_user.sms_marketing_respond = True
            markrting_user.sms_marketing_respond_datetime = \
                datetime.datetime.now()

        # refactor by zhouhl 2018-05-31
        # 判断是否竞价成功的工程商拨打虚拟号 或 客户回拨工程商

        # 情况一：工程商拨打虚拟号
        tmp_virtual_number = VirtualNumber.get_by_args(
            tel_b=caller,
            tel_a=called,
            tel_x=called_show,
            for_sms=False,
            valid=VirtualNumberValid.VALID.value
        )
        supplier = User.get_by_args(mobile=caller)
        # 情况二：客户回拨工程商
        if not tmp_virtual_number or not supplier:
            tmp_virtual_number = VirtualNumber.get_by_args(
                tel_a=caller,
                tel_b=called,
                tel_x=called_show,
                for_sms=False,
                valid=VirtualNumberValid.VALID.value
            )
            supplier = User.get_by_args(mobile=called)

        if tmp_virtual_number and tmp_virtual_number.demand_id and supplier:
            # 更新对应 VirtualNumber 的 updated_at，延长使用期限
            tmp_virtual_number.updated_at = get_timestamp()

            # 该工程商的抢单记录相关操作
            demand = Demand.get_by_id(tmp_virtual_number.demand_id)
            partic = Partic.query.filter(
                Partic.demand_id == demand.id,
                Partic.supplier_id == supplier.id,
                Partic.status == ParticStatus.SUCCEED.value
            ).first()

            if partic:
                # NOTE by chenhj at 2018/4/25 派单不发跟进信息
                # NOTE by ld_wu 2017-12-26 只有首次通话成功才会发模板消息
                if (
                    partic.contact_seconds <= 1
                    and record.call_duration > 0
                    and partic.demand_status not in (
                        DemandStatus.DISPATCHING.value,
                        DemandStatus.MASTER_DISPATCHING.value
                    )
                ):
                    MessageNotify.follow_notify(
                        demand, supplier, called_show, partic, db.session
                    )

                # 更新联系时长
                partic.contact_seconds += record.call_duration or 1

                # NOTE 高并发情况存在数据还没commit，清空缓存后，把旧数据又刷到缓存的情况。故这里先提交db更改，再清空partic缓存
                db.session.commit()
                Partic.clear_demand_partic_cache_data(
                    current_app.redis, demand.id)

        # 若该虚拟号为某企业的推广虚拟号,则按需进行外呼
        from app.enterprise.models import EnterpriseHomepage
        enterprise_hp = EnterpriseHomepage.get_by_args(
            virtual_number=called_show
        )
        if enterprise_hp:
            tmp_outbound_record, err = create_outbound_mission(
                mobile=caller,
                call_reason=CallReason.MARKETING_CALLBACK.value,
                schedule_time=datetime.datetime.now(),
                enterprise_hp=enterprise_hp
            )
            if tmp_outbound_record:
                db.session.add(tmp_outbound_record)

            """
            add by lina at 2018/8/1
            客户联系金银牌企业官网时绑定a*b关系
            """
            enterprise = enterprise_hp.enterprise
            vir_num_record = VirtualNumber.query.filter(
                VirtualNumber.tel_a == caller,
                VirtualNumber.tel_b == called,
                VirtualNumber.valid == VirtualNumberValid.VALID.value,
            ).first()
            if vir_num_record:
                tel_x = vir_num_record.tel_x
            else:
                vir_num_list = VirtualNumber.query.filter(
                    or_(
                        VirtualNumber.tel_a.in_([caller, called]),
                        VirtualNumber.tel_b.in_([caller, called]),
                    ),
                    VirtualNumber.valid == VirtualNumberValid.VALID.value,
                ).all()
                vir_num_record = NumberPoolForLT.query.filter(
                    NumberPoolForLT.tel.notin_([each.tel_x for each in vir_num_list]),
                    NumberPoolForLT.enterprise_id == 0,
                    NumberPoolForLT.reserved.is_(False),
                    NumberPoolForLT.deleted_at == 0
                ).order_by(NumberPoolForLT.updated_at.asc()).first()
                vir_num_record.use_count += 1
                # TODO 考虑虚拟号不够，待补充
                VirtualNumber.create(
                    tel_a=caller,
                    tel_b=called,
                    tel_x=vir_num_record.tel
                )
                tel_x = vir_num_record.tel
            content_for_called = '您好，刚与您通话的客户虚拟号为{}，请用万屏汇绑定的手机号码联系。'.format(tel_x)
            content_for_caller = '您好，{company}的联系电话{telephone}，请注意保存商家电话'.format(
                company=enterprise.remark or enterprise.enterprise_name, telephone=tel_x
            )
            current_app.alliance_producer.send(
                json.dumps({
                    'mobile': called,
                    'content': content_for_called,
                })
            )
            current_app.alliance_producer.send(
                json.dumps({
                    'mobile': caller,
                    'content': content_for_caller,
                })
            )

    except Exception as e:
        print(e)

    response = {
        'code': 0,
        'message': '',
    }
    return jsonify(response)


@axb_bp.route('/query_sms_number', methods=['POST'])
def query_sms_number():
    """
    短信号码查询，联通实时模式
    """
    data = request.get_json()
    query_sms_number_record = QuerySmsNumberRecord.create(**data)
    # 真实发送号
    sender = data['sender']
    # 接收虚拟号
    receiver = data['receiver']

    code = -1
    message = ''
    receiver_show = ''
    sender_show = ''

    # STEP1. 查询axb关系
    # 先判断是否工程商发送短信
    # 在判断是否客户发送短信
    vir_num_record = VirtualNumber.get_by_args(
        tel_b=sender,
        tel_x=receiver,
        valid=VirtualNumberValid.VALID.value,
        for_sms=False,
    )
    if vir_num_record:
        code = 0
        receiver_show = vir_num_record.tel_a
        sender_show = vir_num_record.tel_x
    else:
        vir_num_record = VirtualNumber.get_by_args(
            tel_a=sender,
            tel_x=receiver,
            valid=VirtualNumberValid.VALID.value,
            for_sms=False,
        )
        if vir_num_record and vir_num_record.tel_b != '':
            code = 0
            receiver_show = vir_num_record.tel_b
            sender_show = vir_num_record.tel_x

    # STEP2. 查询axn关系，用于营销短信发送
    if code == -1:
        vir_num_record = VirtualNumber.get_by_args(
            tel_x=receiver,
            tel_b='',
            valid=VirtualNumberValid.VALID.value,
            for_sms=True,
        )
        if (
            vir_num_record
            and sender != vir_num_record.tel_a
            and str(sender)[:3] == '106'
        ):
            code = 0
            receiver_show = vir_num_record.tel_a
            sender_show = vir_num_record.tel_x
            # add by zhouhl 2018-06-28 营销短信查询完号码后，直接解绑
            # vir_num_record.valid = VirtualNumberValid.INVALID.value
        else:
            code = 404
            message = '无绑定关系'

    query_sms_number_record.return_code = code
    query_sms_number_record.return_tel = receiver_show
    query_sms_number_record.return_message = message
    response = {
        'code': code,
        'message': message,
        'data': {
            'receiver_show': receiver_show,
            'sender_show': sender_show,
            'other': {},
        },
    }
    return jsonify(response)


@axb_bp.route('/push_sms_order', methods=['POST'])
def push_sms_order():
    """
    短信记录推送，联通实时模式
    """
    try:
        data = request.get_json()
        SmsOrder.create(**data)

        # add by zhouhl 2017-10-24
        # 短信营销的工程商回复短信，将其标记为有回应
        sender = data['sender']
        marketing_user = User.get_by_args(
            mobile=sender,
            sms_marketing_obj=True,
            sms_marketing_respond=False,
        )
        if marketing_user:
            marketing_user.sms_marketing_respond = True
            marketing_user.sms_marketing_respond_datetime = datetime.datetime.now()

        # add by zhouhl 2017-12-13
        # 如果是百度自定义表单的表单线索短信记录，则进行相应处理
        # 提供给 SEM 固定的虚拟号 18618207054 18618226248 18618226842
        sender_show = data['sender_show']
        if str(sender_show) in ['18618207054', '18618226248', '18618226842', '18618221490']:
            sms_content = data['sms_content']
            print('*' * 50)
            tmp_sms_content = sms_content.encode('utf-8')
            print(tmp_sms_content)
            print('*' * 50)

            # '18618226842' 是忠哥用的信息流表单，里面没有空格，这里简单处理一下
            if str(sender_show) in ['18618207054', '18618226248']:
                nickname = re.search('(?<=姓名 ：)\S+', sms_content)
                nickname = nickname.group()
                nickname = nickname.split(':')[-1]
                nickname = nickname.split('：')[-1]
                nickname = nickname or '新客户(请填写)'

                mobile = re.search('(?<=联系方式 ：)\S+', sms_content)
                mobile = mobile.group()
                mobile = mobile.split(':')[-1]
                mobile = mobile.split('：')[-1]
            else:
                # 信息流表单特殊处理
                nickname = re.search('(?<=姓名:)\S+?;', sms_content)
                nickname = nickname.group()
                nickname = nickname.split(';')[0]

                mobile = re.search('(?<=[联系方式|电话]:)\S+?;', sms_content)
                mobile = mobile.group()
                mobile = mobile.split(';')[0]

            user = User.get_by_args(mobile=mobile)
            if not user:
                # 新客户默认是北京市
                user = User.create(
                    mobile=mobile,
                    nickname=nickname,
                    prov='北京市',
                    city='北京市',
                    area_id='110100',
                    type=UserType.CLIENT.value
                )

            DemandClient.visit(
                user.id,
                DemandClientSource.BAIDU_FORM.value,
                sender_show=str(sender_show)
            )
            tmp_outbound_record, err = create_outbound_mission(
                mobile=user.mobile,
                call_reason=CallReason.XUNKE_CALLBACK.value,
                schedule_time=datetime.datetime.now(),
                user_id=user.id
            )
            if tmp_outbound_record:
                db.session.add(tmp_outbound_record)

    except Exception as e:
        print(e)

    response = {
        'code': 0,
        'message': '',
    }
    return jsonify(response)


